/*
 * Created on Feb 11, 2005
 * Created by dfhuynh
 */
package edu.mit.simile.longwell.query.project;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;

import edu.mit.simile.longwell.Profile;
import edu.mit.simile.longwell.schema.IStructuredSchema;

/**
 * @author dfhuynh
 */
public class SchemaBasedProjector extends ProjectorBase {
	/**
	 * @param profile
	 */
	public SchemaBasedProjector(Profile profile, String parameter, String locale) {
		super(profile);
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjector#isEfficientForRootProjection()
	 */
	public boolean isEfficientForRootProjection() {
		return true;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjector#getUniqueness()
	 */
	public float getUniqueness() {
		return 0;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjector#getParameter()
	 */
	public String getParameter() {
		return "";
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjector#getLabel(java.lang.String)
	 */
	public String getLabel(String locale) {
		ResourceBundle resources = ResourceBundle.getBundle(
			this.getClass().getName(),
			locale == null ? Locale.getDefault() : new Locale(locale));

		return resources.getString("SchemaLabel");
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.ProjectorBase#internalProject(java.util.Set)
	 */
	protected IProjection internalProject(Set objects) {
		return new RootSchemaProjection(objects);
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.ProjectorBase#internalProject()
	 */
	protected IProjection internalProject() {
		return new RootSchemaProjection(null);
	}
	
	protected class RootSchemaProjection implements IProjection {
		final protected Set m_objects;
		
		protected RootSchemaProjection(Set objects) {
			m_objects = objects;
		}
		
		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#getValues()
		 */
		public Set getValues() {
			return getSchemas(m_objects);
		}

		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#getValue(com.hp.hpl.jena.rdf.model.Resource)
		 */
		public Object getValue(Resource object) {
			return getSchema(object);
		}

		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#getObjects()
		 */
		public Set getObjects() {
			if (m_objects != null) {
				return m_objects;
			} else {
				return m_profile.getSchemaModel().getAllObjects();
			}
		}

		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#countObjects()
		 */
		public int countObjects() {
			return getObjects().size();
		}

		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#countObjects(java.lang.Object)
		 */
		public int countObjects(Object value) {
			return getObjects(value).size();
		}

		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#getObjects(java.lang.Object)
		 */
		public Set getObjects(Object value) {
			if (value instanceof Resource && !((Resource) value).isAnon()) {
				return getObjectsInSchema((Resource) value, m_objects);
			} else {
				return new HashSet();
			}
		}

		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#countObjectsWithValues(java.util.Set)
		 */
		public int countObjectsWithValues(Set values) {
			return getObjectsWithValues(values).size();
		}

		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#getObjectsWithValues(java.util.Set)
		 */
		public Set getObjectsWithValues(Set values) {
			Set objects = new HashSet();
			Iterator i = values.iterator();
			
			while (i.hasNext()) {
				objects.addAll(getObjects(i.next()));
			}
			return objects;
		}
		
		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#getObjectToValueMap()
		 */
		public Map getObjectToValueMap() {
			throw new InternalError("Not implemented");
		}

		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#getLocale()
		 */
		public String getLocale() {
			return "";
		}

		/* (non-Javadoc)
		 * @see edu.mit.simile.longwell.query.project.IProjection#getUniqueness()
		 */
		public float getUniqueness() {
			return 0;
		}

		@Override
		public String getProperty() {
			// TODO Auto-generated method stub
			return null;
		}
	}
	
	protected Resource getSchema(Resource object) {
		Iterator i =
			m_profile.getSchemaModel().guessSchemasOfResource(object).iterator();
		
		if (i.hasNext()) {
			return m_profile.getModel().createResource(
					((IStructuredSchema) i.next()).getURI());
		} else {
			return null;
		}
	}
	
	protected Set getSchemas(Set objects) {
		Set schemas = new HashSet();
		Model model = m_profile.getModel();
		
		if (objects == null) {
			
			Iterator i = m_profile.getSchemaModel()
				.getStructuredSchemas().iterator();
			while (i.hasNext()) {
				schemas.add(
					model.createResource(
						((IStructuredSchema) i.next()).getURI()));
			}
		} else {
			Iterator o = objects.iterator();
			while (o.hasNext()) {
				Resource r = (Resource) o.next();
				
				Iterator i =
					m_profile.getSchemaModel()
						.guessSchemasOfResource(r).iterator();
				
				while (i.hasNext()) {
					schemas.add(
						model.createResource(
								((IStructuredSchema) i.next()).getURI()));
				}
			}
		}
		return schemas;
	}
	
	protected Set getObjectsInSchema(Resource value, Set allObjects) {
		Set objects = m_profile.getSchemaModel()
			.getStructuredSchema(value.getURI()).getObjects();
		
		if (allObjects != null && allObjects != objects) {
			Set objects2 = objects;
			
			objects = new HashSet(objects2);
			objects.retainAll(allObjects);
		}
		return objects;
	}
}
